<template>
  <div style="position: relative">
    <div v-if="!loading && !error">
      <div v-if="type === '2'" class="verify-img-out" :style="{ height: parseInt(setSize.imgHeight) + vSpace + 'px' }">
        <div class="verify-img-panel" :style="{ width: setSize.imgWidth, height: setSize.imgHeight }">
          <img :src="'data:image/png;base64,' + backImgBase" alt=""
            style="width: 100%; height: 100%; display: block; pointer-events: none;" />
          <div class="verify-refresh" @click="refresh" v-show="showRefresh">
            <i class="captcha-icon-refresh"></i>
          </div>
          <transition name="tips">
            <span class="verify-tips" v-if="tipWords" :class="passFlag ? 'suc-bg' : 'err-bg'">{{ tipWords }}</span>
          </transition>
        </div>
      </div>
      <!-- 公共部分 -->
      <div class="verify-bar-area" :style="{
        width: setSize.imgWidth,
        height: barSize.height,
        'line-height': barSize.height,
      }">
        <span class="verify-msg" v-text="text"></span>
        <div class="verify-left-bar" :style="{
          width: leftBarWidth !== undefined ? leftBarWidth : barSize.height,
          height: barSize.height,
          'border-color': leftBarBorderColor,
          transaction: transitionWidth,
        }">
          <span class="verify-msg" v-text="finishText"></span>
          <div class="verify-move-block" @touchstart="start" @mousedown="start" :style="{
            width: barSize.height,
            height: barSize.height,
            'background-color': moveBlockBackgroundColor,
            left: moveBlockLeft,
            transition: transitionLeft,
          }">
            <i :class="['verify-icon', iconClass]" :style="{ color: iconColor }"></i>
            <div v-if="type === '2'" class="verify-sub-block" :style="{
              width: Math.floor((parseInt(setSize.imgWidth) * 47) / 310) + 'px',
              height: setSize.imgHeight,
              top: '-' + (parseInt(setSize.imgHeight) + vSpace) + 'px',
              'background-size': setSize.imgWidth + ' ' + setSize.imgHeight,
            }">
              <img :src="'data:image/png;base64,' + blockBackImgBase" alt="" style="
                  width: 100%;
                  height: 100%;
                  display: block;
                  -webkit-user-drag: none;
                " />
            </div>
          </div>
        </div>
      </div>
    </div>
    <div v-else-if="!error">
      <div style="text-align: center">
        <i class="captcha-icon-refresh captcha-spin" style="opacity:.85"></i>
        <div style="color:#999; margin-top: 10px; font-size: 14px;">加载中...</div>
      </div>
    </div>
    <div v-else>
      <div  style="text-align: center">
        <div style="font-size:14px; color:#f30; margin: 20px auto;">数据获取错误：无法获取安全验证信息</div>
        <a href="javascript:void(0)" @click="refresh">点击重新获取</a>
      </div>
    </div>
  </div>
</template>
<script>
/* eslint-disable*/
/**
 * VerifySlide
 * @description 滑块
 * */
import { aesEncrypt } from "./../utils/ase.js";
import { resetSize, request } from "./../utils/util.js";


export default {
  name: "VerifySlide",
  props: {
    captchaType: {
      type: String,
    },
    type: {
      type: String,
      default: "1",
    },
    //弹出式pop，固定fixed
    mode: {
      type: String,
      default: "fixed",
    },
    vSpace: {
      type: Number,
      default: 5,
    },
    explain: {
      type: String,
      default: "向右滑动完成验证",
    },
    imgSize: {
      type: Object,
      default() {
        return {
          width: "310px",
          height: "155px",
        };
      },
    },
    blockSize: {
      type: Object,
      default() {
        return {
          width: "50px",
          height: "50px",
        };
      },
    },
    barSize: {
      type: Object,
      default() {
        return {
          width: "310px",
          height: "40px",
        };
      },
    },
    captchaGetUrl: {
      type: [String, Function],
      default: '/captcha/get'
    },
    captchaCheckUrl: {
      type: [String, Function],
      default: '/captcha/check'
    },
    params: {
      type: Object,
      default: () => ({})
    }
  },
  data() {
    return {
      loading: true,
      error: null,
      secretKey: "", //后端返回的ase加密,
      passFlag: "", //是否通过的,
      backImgBase: "", //验证码背景,
      blockBackImgBase: "", //验证滑块的背景,
      backToken: "", //后端返回的唯一toke,
      startMoveTime: "", //移动开始的,
      endMovetime: "", //移动结束的,
      tipsBackColor: "", //提示词的背景,
      tipWords: "",
      text: "",
      finishText: "",
      setSize: {
        imgHeight: 0,
        imgWidth: 0,
        barHeight: 0,
        barWidth: 0,
      },
      top: 0,
      left: 0,
      moveBlockLeft: undefined,
      leftBarWidth: undefined,
      // 移动中样式
      moveBlockBackgroundColor: undefined,
      leftBarBorderColor: "#ddd",
      iconColor: undefined,
      iconClass: "captcha-icon-right",
      status: false, //鼠标,
      isEnd: false, //是够验证,
      showRefresh: true,
      transitionLeft: "",
      transitionWidth: "",
      startLeft: 0
    };
  },

  mounted() {
    this.$el.onselectstart = function () {
      return false;
    };
    this.init();
  },

  watch: {
    type() {
      this.init();
    },
  },

  methods: {

    responseFormat(success, data, error = '请求失败'){
      return {
        repCode: !!success ? '0000' : '6111',
        repData: data,
        repMsg: error
      }
    },
    // 请求背景图片和验证图片
    async getPictrue() {
      const { captchaType } = this;
      this.loading = true;
      this.error = null
    
      
      try {
        let res;
        if(typeof this.captchaGetUrl === 'string') {
          res = await request(this.captchaGetUrl, { captchaType })
        } else if(typeof this.captchaGetUrl === 'function') {
          res = await this.captchaGetUrl({captchaType}, this.responseFormat)
          if(!res.repCode || !res.repData) {
            let errorMsg = 'captchaGetUrl必须返回{repCode, repData, repMsg?}'
            console.error(errorMsg)
            throw new Error(errorMsg)
          }
        } else {
          let errorMsg = 'captchaGetUrl不是字符串或者函数'
          console.error(errorMsg)
          throw new Error(errorMsg)
        }
        
        const { repCode, repData, repMsg } = res;
        if (repCode == "0000") {
          const { originalImageBase64, jigsawImageBase64, token, secretKey } =
            repData;
          this.backImgBase = originalImageBase64;
          this.blockBackImgBase = jigsawImageBase64;
          this.backToken = token;
          this.secretKey = secretKey;
        } else {
          this.error = '无法获取安全验证信息';
          this.tipWords = repMsg;
        }
      } catch(e) {
        this.error = '无法获取安全验证信息';
        this.$parent.$emit("error", e);
      } finally {
        this.loading = false
      }
      
    },

    bindEvents() {
      const add = (event, fn) => window.addEventListener(event, fn);
      const remove = (event, fn) => {
        window.removeEventListener(event, fn);
      };

      const move = (e) => this.move(e);
      const end = () => this.end();
      // clear Events
      remove("touchmove", move), remove("mousemove", move);
      remove("touchend", end), remove("mouseup", end);
      // bind Events
      add("touchmove", move), add("mousemove", move);
      add("touchend", end), add("mouseup", end);
    },

    async init() {
      this.text = this.explain;
      await this.getPictrue();
      this.$nextTick(() => {
        let { imgHeight, imgWidth, barHeight, barWidth } = resetSize(this);
        this.setSize = {
          imgHeight,
          imgWidth,
          barHeight,
          barWidth,
        };
        this.$parent.$emit("ready", this);
      });

      this.bindEvents();
    },

    start(e) {
      const barArea = this.$el.querySelector(".verify-bar-area");
      e = e || window.event;
      if (!e.touches) {
        //兼容PC端
        var x = e.clientX;
      } else {
        //兼容移动端
        var x = e.touches[0].pageX;
      }

      this.startLeft = Math.floor(
        x - barArea.getBoundingClientRect().left
      );
      this.startMoveTime = +new Date(); //开始滑动的时间
      if (this.isEnd == false) {
        this.text = "";
        this.moveBlockBackgroundColor = "#337ab7";
        this.leftBarBorderColor = "#337AB7";
        this.iconColor = "#fff";
        e.stopPropagation();
        this.status = true;
      }
    },

    move(e) {
      const barArea = this.$el.querySelector(".verify-bar-area");
      e = e || window.event;
      if (this.status && this.isEnd == false) {
        if (!e.touches) {
          //兼容PC端
          var x = e.clientX;
        } else {
          //兼容移动端
          var x = e.touches[0].pageX;
        }
        var bar_area_left = barArea.getBoundingClientRect().left;
        var move_block_left = x - bar_area_left; //小方块相对于父元素的left值
        if (
          move_block_left >=
          barArea.offsetWidth -
          parseInt(parseInt(this.blockSize.width) / 2) -
          2
        ) {
          move_block_left =
            barArea.offsetWidth -
            parseInt(parseInt(this.blockSize.width) / 2) -
            2;
        }
        if (move_block_left <= 0) {
          move_block_left = parseInt(parseInt(this.blockSize.width) / 2);
        }
        //拖动后小方块的left值
        this.moveBlockLeft = move_block_left - this.startLeft + "px";
        this.leftBarWidth = move_block_left - this.startLeft + "px";
      }
    },

    async end() {
      this.endMovetime = +new Date();
      //判断是否重合
      if (this.status && this.isEnd == false) {
        var moveLeftDistance = parseInt(
          (this.moveBlockLeft || "").replace("px", "")
        );
        moveLeftDistance =
          (moveLeftDistance * 310) / parseInt(this.setSize.imgWidth);
        let data = {
          captchaType: this.captchaType,
          pointJson: this.secretKey
            ? aesEncrypt(
              JSON.stringify({ x: moveLeftDistance, y: 5.0 }),
              this.secretKey
            )
            : JSON.stringify({ x: moveLeftDistance, y: 5.0 }),
          token: this.backToken,
          ...this.params
        };

        let res;
        try {
          if(typeof this.captchaCheckUrl === 'string') {
            res = await request(this.captchaCheckUrl, data)
        } else if(typeof this.captchaCheckUrl === 'function') {
          res = await this.captchaCheckUrl(data, this.responseFormat)
          if(!res.repCode) {
            let errorMsg = 'captchaCheckUrl必须返回{repCode}'
            console.error(errorMsg)
            throw new Error(errorMsg)
          }
        } else {
          let errorMsg = 'captchaCheckUrl不是字符串或者函数'
          console.error(errorMsg)
          throw new Error(errorMsg)
        }

          
          if (res.repCode == "0000") {
              this.moveBlockBackgroundColor = "#5cb85c";
              this.leftBarBorderColor = "#5cb85c";
              this.iconColor = "#fff";
              this.iconClass = "captcha-icon-check";
              this.showRefresh = false;
              this.isEnd = true;
              if (this.mode == "pop") {
                setTimeout(() => {
                  this.$parent.clickShow = false;
                  this.refresh();
                }, 1500);
              }
              this.passFlag = true;
              this.tipWords = `${(
                (this.endMovetime - this.startMoveTime) /
                1000
              ).toFixed(2)}s验证成功`;
              var captchaVerification = this.secretKey
                ? aesEncrypt(
                  this.backToken +
                  "---" +
                  JSON.stringify({ x: moveLeftDistance, y: 5.0 }),
                  this.secretKey
                )
                : this.backToken +
                "---" +
                JSON.stringify({ x: moveLeftDistance, y: 5.0 });
              setTimeout(() => {
                this.tipWords = "";
                this.$parent.closeBox({ captchaVerification });
                this.$parent.$emit("success", { captchaVerification });
              }, 1000);
            } else {
              this.$el.style.pointerEvents = 'none'
              this.moveBlockBackgroundColor = "#d9534f";
              this.leftBarBorderColor = "#d9534f";
              this.iconColor = "#fff";
              this.iconClass = "captcha-icon-close";
              this.passFlag = false;
              setTimeout(() => {
                this.refresh();
              }, 1000);
              // this.$parent.$emit("error", this);
              this.tipWords = "验证失败";
              setTimeout(() => {
                this.tipWords = "";
              }, 1000);
            }
        } catch(e) {
          this.$parent.$emit("error", e);
          this.refresh();
        } finally {
          this.status = false;
        }
      }
    },
    async refresh() {
      this.$el.style.pointerEvents = 'auto'
      this.showRefresh = true;
      this.finishText = "";

      this.transitionLeft = "left .3s";
      this.moveBlockLeft = 0;

      this.leftBarWidth = undefined;
      this.transitionWidth = "width .3s";

      this.leftBarBorderColor = "#ddd";
      this.moveBlockBackgroundColor = "#fff";
      this.iconColor = "#000";
      this.iconClass = "captcha-icon-right";
      this.isEnd = false;

      await this.getPictrue();
      setTimeout(() => {
        this.transitionWidth = "";
        this.transitionLeft = "";
        this.text = this.explain;
      }, 300);
    },
  },
};
</script>
